package com.example.caorl.job2;

import java.lang.reflect.Method;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

public class Homework03 {


    public static void main(String[] args) throws Exception{

        long start=System.currentTimeMillis();
        // 在这里创建一个线程或线程池，
        // 异步执行 下面方法
        int result = sum3(); //这是得到的返回值
/*        Class<?> aClass = Class.forName("com.example.caorl.job2.Homework03");
        Method sum = aClass.getMethod("sum");
        Method[] methods = aClass.getMethods();
        Method sum1 = aClass.getDeclaredMethod("sum1");
        sum1.setAccessible(true);
        Method sum2 = aClass.getDeclaredMethod("sum2");
        sum2.setAccessible(true);
        Method sum3 = aClass.getDeclaredMethod("sum3");
        sum3.setAccessible(true);
        Method sum4 = aClass.getDeclaredMethod("sum4");
        sum4.setAccessible(true);
        Method sum5 = aClass.getDeclaredMethod("sum5");
        sum5.setAccessible(true);
        Method sum6 = aClass.getDeclaredMethod("sum6");
        sum6.setAccessible(true);
        Method sum7 = aClass.getDeclaredMethod("sum7");
        sum7.setAccessible(true);
        Method sum8 = aClass.getDeclaredMethod("sum8");
        sum8.setAccessible(true);
        Method sum9 = aClass.getDeclaredMethod("sum9");
        sum9.setAccessible(true);
        Object invoke = sum.invoke(aClass);
        Object invoke1 = sum1.invoke(aClass);
        Object invoke2 = sum2.invoke(aClass);
        Object invoke3 = sum3.invoke(aClass);
        Object invoke4 = sum4.invoke(aClass);
        Object invoke5 = sum5.invoke(aClass);
        Object invoke6 = sum6.invoke(aClass);
        Object invoke7 = sum7.invoke(aClass);
        Object invoke8 = sum8.invoke(aClass);
        Object invoke9 = sum9.invoke(aClass);
        System.out.println("反射调用结果：" + invoke);
        System.out.println("反射调用结果：" + invoke1);
        System.out.println("反射调用结果：" + invoke2);
        System.out.println("反射调用结果：" + invoke3);
        System.out.println("反射调用结果：" + invoke4);
        System.out.println("反射调用结果：" + invoke5);
        System.out.println("反射调用结果：" + invoke6);
        System.out.println("反射调用结果：" + invoke7);
        System.out.println("反射调用结果：" + invoke8);
        System.out.println("反射调用结果：" + invoke9);*/

        System.out.println(Thread.currentThread().getName());
        // 确保  拿到result 并输出
        System.out.println("异步计算结果为："+result);

        System.out.println("使用时间："+ (System.currentTimeMillis()-start) + " ms");

        // 然后退出main线程
    }

    public static int sum() {
        return fibo(36);
    }


    /**
     * 方法1:Future
     * @return
     */
    private static Integer sum1() {
        Integer res = null;
        ExecutorService executor = Executors.newCachedThreadPool();
        Future<Integer> result = executor.submit(new Callable<Integer>() {
            public Integer call() throws Exception {
                System.out.println("当前计算线程："+Thread.currentThread().getName());
                return fibo(36);
            }
        });
        executor.shutdown(); //必须调用shutdown()方法吗？不关闭是否会存在问题？
        try {

            res = result.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } finally {
            return res;
        }
    }

    /**
     * 方法2:FutureTask
     * @return
     */
    private static Integer sum2() {
        Integer res = null;
        FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println("当前计算线程："+Thread.currentThread().getName());
                return fibo(36);
            }
        });
        new Thread(task).start();
        try {
            res = task.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } finally {
            return res;
        }
    }

    /**
     * 方法3:CompletableFuture
     * @return
     */
    private static Integer sum3() throws Exception {
        /*CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return 36;
        }).thenApplyAsync(v -> {
            System.out.println("当前计算线程："+Thread.currentThread().getName());
            return fibo(v);
        });
        Integer result = null;
        try {
            result = integerCompletableFuture.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return result;*/
        AtomicInteger atomicInteger = new AtomicInteger();
        CompletableFuture completableFuture = new CompletableFuture<Integer>();
        new Thread(()->{
            int fibo = fibo(36);
            atomicInteger.set(fibo);
            System.out.println("=========");
            completableFuture.complete(fibo);
        }).start();
        System.out.println(completableFuture.get());
        return atomicInteger.get();
    }

    /**
     * 方法4:CountDownLatch
     * @return
     */
    private static Integer sum4() {
        AtomicInteger atomicInteger = new AtomicInteger();
        CountDownLatch countDownLatch = new CountDownLatch(1);
        new Thread(() -> {
            System.out.println("当前计算线程："+Thread.currentThread().getName());
            atomicInteger.set(fibo(36));
            countDownLatch.countDown();
        }).start();
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return atomicInteger.get();
    }

    /**
     * 方法5:join()
     * @return
     */
    private static Integer sum5() {
        AtomicInteger atomicInteger = new AtomicInteger();
        Thread thread = new Thread(() -> {
            System.out.println("当前计算线程："+Thread.currentThread().getName());
            atomicInteger.set(fibo(36));
        });
        thread.start();
        try {
            thread.join(); //让出CPU，运行子线程
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return atomicInteger.get();
    }

    /**
     * 方法6:while()判断线程数
     * @return
     */
    private static Integer sum6(){
        int activeCount = Thread.activeCount();
        AtomicInteger atomicInteger = new AtomicInteger();
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("当前计算线程："+Thread.currentThread().getName());
            atomicInteger.set(fibo(36));
        });
        thread.start();
        while (Thread.activeCount()>activeCount){
            Thread.yield();
        }
        return atomicInteger.get();
    }

    /**
     * 方法7：使用isActive阻塞线程
     * @return
     */
    private static Integer sum7(){
        AtomicInteger atomicInteger = new AtomicInteger();
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("当前计算线程："+Thread.currentThread().getName());
            atomicInteger.set(fibo(36));
        });
        thread.start();
        while (thread.isAlive()){}
        return atomicInteger.get();
    }

    /**
     * 方法8：竞争锁阻塞线程
     * @return
     */
    private static Integer sum8(){
        ReentrantLock reentrantLock = new ReentrantLock();
        AtomicInteger atomicInteger = new AtomicInteger();
        Thread thread = new Thread(() -> {
            try {
                reentrantLock.lock();
                System.out.println("当前计算线程："+Thread.currentThread().getName());
                atomicInteger.set(fibo(36));
                reentrantLock.unlock();
                System.out.println("释放锁");
            } catch (Exception e) {
                e.printStackTrace();
            }

        });
        thread.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        while (!reentrantLock.tryLock()){
            System.out.println("获取锁失败");
        }
        return atomicInteger.get();
    }

    /**
     * 方法9：信号量竞争
     * @return
     */
    private static Integer sum9(){
        Semaphore semaphore = new Semaphore(1);
        AtomicInteger atomicInteger = new AtomicInteger();
        Thread thread = new Thread(() -> {
            try {
                semaphore.acquire();
                System.out.println("当前计算线程："+Thread.currentThread().getName());
                atomicInteger.set(fibo(36));
                semaphore.release();
                System.out.println("释放锁");
            } catch (Exception e) {
                e.printStackTrace();
            }

        });
        thread.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        while (!semaphore.tryAcquire()){
            System.out.println("获取锁失败");
        }
        return atomicInteger.get();
    }



    public static int fibo(int a) {
        if ( a < 2)
            return 1;
        return fibo(a-1) + fibo(a-2);
    }
}
